Posts

Post marked as solved
2 Replies
Thank you for your revert Claude. As far as I see, connection is a requirement for scanning BLE devices in the background.
Post not yet marked as solved
6 Replies
I have made the "func getWeatherData" global like "func fetchWeather" and I'm still getting the same error. I can e-mail you the project. onurduzova@gmail.com
Post not yet marked as solved
6 Replies
Thank your for your guidance but I'm having trouble with accessing "fetchWeather" in "class ViewModel" from "class Coordinator" because "class Coordinator" is within the "struct SearchBar" and therefore I can't subclass such as "class Coordinator: ViewModel". In line "13" I'm getting the "Use of unresolved identifier 'ViewModel' " error. Would you have any suggestion regarding the accessibility ? struct SearchBar: UIViewRepresentable {      @Binding var text: String      class Coordinator: NSObject, UISearchBarDelegate {          @ObservedObject var viewModel = ViewModel()          @Binding var text: String          init(text: Binding<String>) {       _text = text     }          func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {       text = searchText     }          func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {              viewModel.fetchWeather(cityName: text)     } } class ViewModel: ObservableObject { func fetchWeather(cityName: String) {       let urlString = "\(weatherURL)&query=\(cityName)"       getWeatherData(with: urlString)     }   }
Post not yet marked as solved
6 Replies
I took the "fetchWeather" out of the "class ViewModel" and I'm still getting the same error.   public func fetchWeather(cityName: String) {     let urlString = "\(ViewModel().weatherURL)&query=\(cityName)"     ViewModel().getWeatherData(with: urlString)   } struct SearchBar: UIViewRepresentable {      @Binding var text: String      class Coordinator: NSObject, UISearchBarDelegate {     @Binding var text: String     init(text: Binding<String>) {       _text = text     }     func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {       text = searchText     }     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {       fetchWeather(cityName: text)     }   }
Post marked as solved
7 Replies
Thanks very much Claude.
Post marked as solved
7 Replies
I first tried with the outlet but the result didn't change. I added the "Spinner.stop()" in "func spinnerSetup()" before the segue. But the outcome remains the same.import UIKit class StitchEffectViewController: UIViewController { // @IBOutlet weak var activityIndicator: UIActivityIndicatorView! let stitchPhotoID = "StitchPhotoID" @IBOutlet weak var tapAboveOutlet: UIButton! override func viewDidLoad() { super.viewDidLoad() // activityIndicator.isHidden = true // activityIndicator.hidesWhenStopped = true } // override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { // super.viewWillTransition(to: size, with: coordinator) // // if UIApplication.shared.applicationState == .inactive { // Spinner.update() // } // // } @IBAction func tapAbove(_ sender: UIButton) { Spinner.start(style: .large, backColor: UIColor.white, baseColor: UIColor.green) spinnerSetup() } func spinnerSetup() { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { Spinner.stop() self.performSegue(withIdentifier: self.stitchPhotoID, sender: nil) }) } }
Post marked as solved
7 Replies
Hi Claude, yes I expect that because all the photo effects and objc funcs are slowing the app down. Regarding the block, I've been trying to make the activityIndicator(Spinner.start) to show up before the app freezes due to the segue operation. The activityIndicator shows up after the segue on the next viewController making that viewController irresponsive. import Foundation import UIKit open class Spinner { internal static var spinner: UIActivityIndicatorView? public static var style: UIActivityIndicatorView.Style = .large public static var baseBackColor = UIColor(white: 0, alpha: 0.6) public static var baseColor = UIColor.red public static func start(style: UIActivityIndicatorView.Style = style, backColor: UIColor = baseBackColor, baseColor: UIColor = baseColor) { if spinner == nil, let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first { let frame = UIScreen.main.bounds spinner = UIActivityIndicatorView(frame: frame) spinner!.backgroundColor = backColor spinner!.style = style spinner?.color = baseColor window.addSubview(spinner!) spinner!.startAnimating() // NotificationCenter.default.addObserver(self, selector: #selector(update), name: NSNotification.Name.AVCaptureDeviceWasDisconnected, object: nil) } } public static func stop() { if spinner != nil { spinner!.stopAnimating() spinner!.removeFromSuperview() spinner = nil } } // @objc public static func update() { // if Spinner.spinner != nil { // Spinner.stop() // Spinner.start() // } // } }
Post not yet marked as solved
4 Replies
Thank you very much, have a great weekend !
Post not yet marked as solved
4 Replies
Hi Claude, thank you for your response. Regarding the call of "applyFilterTo".@objcprivatefunc sliderNoiseDidChange(_ sender: UISlider!, image: UIImage,_ event: UIEvent) { if let touchEvent = event.allTouches?.first { switch touchEvent.phase { case .moved: labelControl.text = String(displayInPercentage) if updatedImage == nil { updatedImage = effects.applyFilterTo(image: pickedImage!, filterEffect: Effects.Filter(filterName: "CIUnsharpMask", filterEffectValue: nil, filterEffectValueName: nil), sliderValue: CGFloat(sender.value)) } else { updatedImage = effects.applyFilterTo(image: updatedImage!, filterEffect: Effects.Filter(filterName: "CIUnsharpMask", filterEffectValue: nil, filterEffectValueName: nil), sliderValue: CGFloat(sender.value)) } case .ended: if segmentedControl.selectedSegmentIndex == 3 { updatedImage = photoImageView.image UserDefaults.standard.setValue(sliderControl.value, forKey: "slider_noise") } default: break } } labelControl.textAlignment = .center labelControl.numberOfLines = 0 labelControl.textColor = UIColor.gray labelControl.font = UIFont.systemFont(ofSize: 16) labelControl.translatesAutoresizingMaskIntoConstraints = false view.addSubview(labelControl) NSLayoutConstraint.activate([labelControl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30), labelControl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30), labelControl.bottomAnchor.constraint(equalTo: resetConfirmCollectionView.topAnchor, constant: -80)]) }
Post marked as solved
17 Replies
Following up on the changes, I get this error in the console; (That actually happens from time to time, I really hope so.)[UICollectionView] Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (2) must be equal to the number of items contained in that section before the update (2), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). - will perform reloadData. UICollectionView instance: &lt;UICollectionView: 0x7fa54789d400; frame = (0 742; 375 70); clipsToBounds = YES; gestureRecognizers = &lt;NSArray: 0x600000337660&gt;; layer = &lt;CALayer: 0x600000dcf6e0&gt;; contentOffset: {0, 0}; contentSize: {375, 133.75}; adjustedContentInset: {0, 0, 34, 0}; layout: &lt;UICollectionViewFlowLayout: 0x7fa54663f890&gt;; dataSource: &lt;"appName".PhotoViewController: 0x7fa54666bc50&gt;&gt;; currentUpdate: [UICollectionViewUpdate - 0x7fa546662ef0: old:&lt;UICollectionViewData: 0x60000343dc00&gt; new&lt;UICollectionViewData: 0x600003433b80&gt; items:&lt;( "I(0,0)")&gt;]func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell { if collectionView == resetConfirmCollectionView { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResetConfirmCellID", for: indexPath) as! ResetConfirmCell let config = UIImage.SymbolConfiguration(pointSize: 40, weight: .semibold) if indexPath.row == 0 { guard let cellImage = UIImage(systemName: "multiply", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } if dataPassed?.row == 1 { let cellCount = resetConfirmCollectionView.visibleCells.count let item = cellCount - 1 let cellIndexPath = IndexPath(item: item, section: 0) resetConfirmCollectionView.insertItems(at: [cellIndexPath]) guard let cellImage = UIImage(systemName: "pencil", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } if indexPath.row == 1 { print("Passed on row 1") guard let cellImage = UIImage(systemName: "checkmark", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } }
Post marked as solved
17 Replies
The problem at its' core is "previousViewController.dataPassed = self.collectionViewEffects.indexPathsForSelectedItems?.first" is sending out this info; "Optional([0, 1])" when I tap "indexPath.row = 1", I need to receive only 1 indexPath.row, the one that I tap. That's why "if dataPassed!.row == 1" never gets triggered.class EffectsViewController: UIViewController { override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "EffectsPhotoSegue" { if let previousViewController = segue.destination as? PhotoViewController { previousViewController.dataPassed = self.collectionViewEffects.indexPathsForSelectedItems?.first } } } } class PhotoViewController: UIViewController { var dataPassed: IndexPath? func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell { if collectionView == resetConfirmCollectionView { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResetConfirmCellID", for: indexPath) as! ResetConfirmCell let config = UIImage.SymbolConfiguration(pointSize: 40, weight: .semibold) if indexPath.row == 0 { guard let cellImage = UIImage(systemName: "multiply", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } if indexPath.row == 1 { print("Passed on row 1") guard let cellImage = UIImage(systemName: "checkmark", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } if dataPassed!.row == 1 { let cellCount = resetConfirmCollectionView.visibleCells.count let item = cellCount - 1 let cellIndexPath = IndexPath(item: item, section: 0) resetConfirmCollectionView.insertItems(at: [cellIndexPath]) guard let cellImage = UIImage(systemName: "pencil", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } } }
Post marked as solved
17 Replies
The breakpoint hits when the "effectsViewController" is about to pop up and I receive the print statement. Then, when I tap in both of the "indexPath.row = 0" &amp;&amp; "indexPath.row = 1", the breakpoint hits and I receive the print statement again.
Post marked as solved
17 Replies
Following up on your guidance I think I'm on the right track. I have removed notifications and added the "dataPassed" variable. I also removed the "effectsMenuCollectionView", instead of that I'm using "resetConfirmCollectionView". Even though I'm tapping on "row = 1" in "collectionViewEffects", I can't trigger the breakpoint I set in line47. Do you see any error or adjustment to be made ? class PhotoViewController: UIViewController, UIScrollViewDelegate { var dataPassed: IndexPath? override func viewDidLoad() { super.viewDidLoad() resetConfirmCollectionView.reloadData() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "PhotoEffectsSegue" { if let nextViewController = segue.destination as? EffectsViewController { DispatchQueue.main.async { nextViewController.effectsImageView = self.photoImageView nextViewController.effectsImage = self.filteredImage nextViewController.pickedEffectsImage = self.pickedImage } } } } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell { if collectionView == resetConfirmCollectionView { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResetConfirmCellID", for: indexPath) as! ResetConfirmCell let config = UIImage.SymbolConfiguration(pointSize: 40, weight: .semibold) if indexPath.row == 0 { guard let cellImage = UIImage(systemName: "multiply", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } if indexPath.row == 1 { guard let cellImage = UIImage(systemName: "checkmark", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } if dataPassed!.row == 1 { let cellCount = resetConfirmCollectionView.visibleCells.count let item = cellCount - 1 let cellIndexPath = IndexPath(item: item, section: 0) resetConfirmCollectionView.insertItems(at: [cellIndexPath]) guard let cellImage = UIImage(systemName: "pencil", withConfiguration: config) else { print("SystemImage not available") return cell } cell.resetConfirmImage = cellImage return cell } } class EffectsViewController: UIViewController { override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "EffectsPhotoSegue" { if let previousViewController = segue.destination as? PhotoViewController { DispatchQueue.main.async { previousViewController.dataPassed = self.collectionViewEffects.indexPathsForSelectedItems?.first previousViewController.photoImageView.image = self.effectsImageView!.image previousViewController.filteredImage = self.effectsImage previousViewController.pickedImage = self.pickedEffectsImage previousViewController.effectsSegmentedControl() (previousViewController.menuStackView).isHidden = true resetConfirmCollectionView.isHidden = false } } } } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if collectionView == collectionViewEffects { if indexPath.row == 0 { effectsImageView!.image = pickedEffectsImage self.performSegue(withIdentifier: "EffectsPhotoSegue", sender: self) } if indexPath.row == 1 { let imageViewHeight: CGFloat = effectsImageView!.image!.size.height let imageViewWidth: CGFloat = effectsImageView!.image!.size.width effectsImage = effects.cropToBounds(image: effectsImageView!.image!, width: Double(imageViewWidth), height: Double(imageViewHeight)) self.performSegue(withIdentifier: "EffectsPhotoSegue", sender: self) } } }
Post marked as solved
17 Replies
I tried that and I've had the same problem because if I'm not mistaken, all the changes must take place within the "@objc func updateCollectionView0(notification: NSNotification)". I think need a way to reach "let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "EffectsMenuCellID", for: indexPath) as! EffectsMenuCell" within @objc func block, then implement an adaptive layout size according to the number of items added and also didSelect for the new item added. I don't know this seems pretty advanced stuff for me.